package se.ytterman.jserial.examples.gsm;

import java.lang.*;
import java.util.*;
import java.util.concurrent.*;
import java.io.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;

import se.ytterman.jserial.framework.device.*;
import se.ytterman.jserial.framework.fsm.*;

import se.ytterman.jserial.io.CommunicationAdapter;
import se.ytterman.jserial.util.DOMUtil;

public class GSMPhone {

    public GSMPhone(CommunicationAdapter commAdapter, 
                    String tokenModelPath,
                    String stateModelPath) {      
        /* Define queues */
        
        // Device request queue
        PriorityBlockingQueue deviceRequestQueue = new PriorityBlockingQueue();
        
        // Device response queue
        PriorityBlockingQueue deviceResponseQueue = new PriorityBlockingQueue();
        
        // API request queue
        PriorityBlockingQueue apiRequestQueue = new PriorityBlockingQueue();
        
        // API response queue
        PriorityBlockingQueue apiResponseQueue = new PriorityBlockingQueue();
        
        
        try{                      
            /* Load token model */
            
            // Create token model DOM tree from file
            Document tokenModel = DOMUtil.parseXMLFile(tokenModelPath);          
            
            // Load information from XML token definition
            ResponseFactory responseFactory = new ResponseFactory(tokenModel);
            RequestFactory requestFactory = new RequestFactory(tokenModel);
            
            // Load device communication threads with format information
            responseFactory.loadModel();
            requestFactory.loadModel();
            
            /* Define threads */
        
            // Sender thread    
            this.phoneSender = new DeviceInputThread(commAdapter, deviceRequestQueue);

            // Listener thread
            this.phoneListener = new DeviceOutputThread(commAdapter, 
                                                        responseFactory, 
                                                        deviceResponseQueue);                 
            
            /* Create statemachine */
            
            // State machine thread
            this.deviceMachine = new DeviceStateMachine(deviceRequestQueue,
                                                    deviceResponseQueue,
                                                    apiRequestQueue,
                                                    apiResponseQueue,
                                                    requestFactory);
            /* Define API */
        
            // Application API interface
            this.phoneApi = new GSMPhoneApi(apiRequestQueue,
                                            apiResponseQueue);
            
            /* Load statemachine */
            
            // Create statemachine model DOM tree from file
            Document fsmModel = DOMUtil.parseXMLFile(stateModelPath);
            
            // Load and create states (Pass 1)
            this.deviceMachine.loadStates(fsmModel);
            
            // Load and create state dependencies (Pass 2)
            this.deviceMachine.loadDependencies(fsmModel);
        
            /* Start threads */
            if(true) {
                // Start listener thread
                this.phoneListener.start();
        
                // Start sender thread
                this.phoneSender.start();
        
                // Start fsm thread
                this.deviceMachine.start();
            }
        }
	catch(Exception e) {
            System.out.println("Parsing token model:" + e.getMessage());
            e.printStackTrace();
        }
    }

    public GSMPhoneApi getGSMPhoneApi() {
        return this.phoneApi;
    }

    // Sender thread
    DeviceInputThread phoneSender;
    
    // Listener thread
    DeviceOutputThread phoneListener;
    
    // State macine thread
    DeviceStateMachine deviceMachine;
    
    // User API interface
    GSMPhoneApi phoneApi;
}
